package com.wwf.filter;

import com.wwf.pojo.IpAccessLog;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.http.HttpMethod;
import org.springframework.http.HttpStatus;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

import java.net.URI;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicInteger;

@Slf4j
@Component
@RefreshScope
public class IPRateFilter implements GlobalFilter, Ordered {
    private static Map<String, List<IpAccessLog>> ipAccessLogMap = new ConcurrentHashMap<String, List<IpAccessLog>>();
    private static Map<String, AtomicInteger> ipAccesCount = new ConcurrentHashMap<>();
    private static long rateTime = 10*60*1000;
    @Value("${iprate.num}")
    private int rateipnum;
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        ServerHttpRequest request = exchange.getRequest();
        ServerHttpResponse response = exchange.getResponse();
        String clientIp = request.getRemoteAddress().getHostString();
        List<IpAccessLog> ipAccessLogs = ipAccessLogMap.get(clientIp);
        AtomicInteger currrentIpAcessCount = ipAccesCount.get(clientIp);
        Date currentDate = new Date();
        if( null == currrentIpAcessCount){
            currrentIpAcessCount = new AtomicInteger(0);
            ipAccesCount.put(clientIp,currrentIpAcessCount);
        }
        synchronized (clientIp){
            if(ipAccessLogs !=null){
                for (IpAccessLog ipAccessLog : ipAccessLogs) {
                    Date accessTime = ipAccessLog.getAccessTime();
                    if(accessTime.getTime()+rateTime<currentDate.getTime()){//访问时间超过10分钟
                        ipAccessLogs.remove(ipAccessLog);
                        if(currrentIpAcessCount.intValue()>0){
                            currrentIpAcessCount.decrementAndGet();
                        }
                    }else{//10分钟内的
                        currrentIpAcessCount.incrementAndGet();
                    }
                }
            }else {
                ipAccessLogs=new ArrayList<IpAccessLog>();
            }
            IpAccessLog ipAccessLog = new IpAccessLog();
            ipAccessLog.setIp(clientIp);
            ipAccessLog.setAccessTime(currentDate);
            ipAccessLogs.add(ipAccessLog);
            ipAccessLogMap.put(clientIp,ipAccessLogs);
            if(currrentIpAcessCount.intValue()>rateipnum){
                // 决绝访问，返回
                response.setStatusCode(HttpStatus.FORBIDDEN); // 状态码
                String data = "Request be denied!";
                DataBuffer wrap = response.bufferFactory().wrap(data.getBytes());
                return response.writeWith(Mono.just(wrap));
            }
        }

        return chain.filter(exchange);
    }

    @Override
    public int getOrder() {
        return 0;
    }
}
